/*
 * libPaquetes.c
 *
 *  Created on: 30/11/2011
 *      Author: utn_so
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "tiposPaquetes.h"

uint64_t potencia(uint16_t base, uint16_t exponente) {
	uint64_t res = 1;
	uint16_t i;
	for (i = 1; i <= exponente; i++) {
		res *= base;
	}
	return res;
}

//--------------------------------------------------
//MANEJO DE PAQUETES GENERICO
//--------------------------------------------------

int8_t empaquetar(char* cadena, t_paquete* paquete) {
	memcpy(&((*paquete).type), cadena, 1);
	(*paquete).pLength = ((uint8_t) cadena[1]) * 256 + ((uint8_t) cadena[2]);
	(*paquete).payLoad = (char*) malloc(sizeof(char) * (*paquete).pLength + 1);
	memcpy(((*paquete).payLoad), cadena + 3, ((*paquete).pLength));
	(*paquete).payLoad[(*paquete).pLength] = '\0';

	return 0;
}

int8_t desempaquetar(t_paquete paquete, char** cadena) {
	(*cadena) = (char*) malloc(paquete.pLength + 3);
	(*cadena)[0] = paquete.type;
	div_t division = div(paquete.pLength, 256);
	(*cadena)[1] = division.quot;
	(*cadena)[2] = division.rem;
	uint32_t i;
	for (i = 3; i < paquete.pLength + 3; i++) {
		(*cadena)[i] = paquete.payLoad[i - 3];
	}
	return 0;
}

//--------------------------------------------------
//DETECCION DE TIPO DE PAQUETE
//--------------------------------------------------

int8_t esPaqueteHandShake(uint8_t tipo) {
	//<0><uint16_t><>
	if (tipo == TIPO_HANDSHAKE
	)
		return 1;
	else
		return 0;
}

int8_t esPaqueteEscritura(uint8_t tipo) {
	//<1><uint16_t><{<uint64_t><contenidoSector>}>
	if (tipo == TIPO_ESCRITURA
	)
		return 1;
	else
		return 0;
}

int8_t esPaqueteLectura(uint8_t tipo) {
	//<2><uint16_t><{<uint64_t>}>
	if (tipo == TIPO_LECTURA
	)
		return 1;
	else
		return 0;
}

int8_t esPaqueteError(uint8_t tipo) {
	if (tipo == TIPO_ERROR
		)
		return 1;
	else
		return 0;
}

int8_t esPaqueteTiempo(uint8_t tipo){
	if(tipo == TIPO_TIEMPO){
		return 1;
	}else{
		return 0;
	}
}

//--------------------------------------------------
//MANEJO DE PAQUETES DE ESCRITURA
//--------------------------------------------------

int8_t paqueteAPaqueteEscritura(t_paquete paquete, t_paquete_escritura* paqueteEscritura) {
	/*--------------------------------------------------
	 * ESTA FUNCION PASA UNA ESTRUCTURA PAQUETE GENERICO
	 * A UNA PAQUETE DE ESCRITURA
	 * --------------------------------------------------
	 */
	if (esPaqueteEscritura(paquete.type)) {
		(*paqueteEscritura).type = paquete.type;
		(*paqueteEscritura).pLength = paquete.pLength;
		(*paqueteEscritura).payLoad = (payLoad_Escritura*) malloc(paquete.pLength / sizeof(payLoad_Escritura));
		uint32_t i; //INDICE PARA CHAR
		uint32_t j; //INDICE PARA PAYLOAD_ESCRITURA
		for (i = 0, j = 0; (j < (paquete.pLength / sizeof(payLoad_Escritura))) && (i < (paquete.pLength - 519)); j++) {
			((*paqueteEscritura).payLoad[j]).numSector = (((uint8_t) paquete.payLoad[i]) * potencia(2, 56));
			((*paqueteEscritura).payLoad[j]).numSector += (((uint8_t) paquete.payLoad[i + 1]) * potencia(2, 48));
			((*paqueteEscritura).payLoad[j]).numSector += (((uint8_t) paquete.payLoad[i + 2]) * potencia(2, 40));
			((*paqueteEscritura).payLoad[j]).numSector += (((uint8_t) paquete.payLoad[i + 3]) * potencia(2, 32));
			((*paqueteEscritura).payLoad[j]).numSector += (((uint8_t) paquete.payLoad[i + 4]) * potencia(2, 24));
			((*paqueteEscritura).payLoad[j]).numSector += (((uint8_t) paquete.payLoad[i + 5]) * potencia(2, 16));
			((*paqueteEscritura).payLoad[j]).numSector += (((uint8_t) paquete.payLoad[i + 6]) * potencia(2, 8));
			((*paqueteEscritura).payLoad[j]).numSector += (((uint8_t) paquete.payLoad[i + 7]));
			i += 8;

			uint32_t k;
			for (k = 0; (k < 512) && (i < paquete.pLength); i++, k++)
				(((*paqueteEscritura).payLoad[j]).contenidoSector)[k] = paquete.payLoad[i];
		}
		return 0;
	} else
		return 1;
}

int8_t paqueteEscrituraAPaquete(t_paquete_escritura paqueteEscritura, t_paquete* paquete) {
	/*--------------------------------------------------
	 * ESTA FUNCION PASA UNA ESTRUCTURA PAQUETE DE ESCRITURA
	 * A UNA PAQUETE GENERICO
	 * --------------------------------------------------
	 */
	if (esPaqueteEscritura(paqueteEscritura.type)) {
		(*paquete).type = paqueteEscritura.type;
		(*paquete).pLength = paqueteEscritura.pLength;
		(*paquete).payLoad = (char*) malloc(paqueteEscritura.pLength);
		uint32_t i; //INDICE PARA CHAR
		uint32_t j; //INDICE PARA UINT64_T
		for (i = 0, j = 0; (i < paqueteEscritura.pLength - 519) && (j < (paqueteEscritura.pLength / sizeof(payLoad_Escritura))); j++) {
			(*paquete).payLoad[i] = paqueteEscritura.payLoad[j].numSector / potencia(2, 56);
			(*paquete).payLoad[i + 1] = (paqueteEscritura.payLoad[j].numSector / potencia(2, 48)) - (((uint8_t) (*paquete).payLoad[i]) * potencia(2, 8));
			(*paquete).payLoad[i + 2] = (paqueteEscritura.payLoad[j].numSector / potencia(2, 40)) - ((((uint8_t) (*paquete).payLoad[i]) * potencia(2, 16)) + (((uint8_t) (*paquete).payLoad[i + 1]) * potencia(2, 8)));
			(*paquete).payLoad[i + 3] = (paqueteEscritura.payLoad[j].numSector / potencia(2, 32)) - ((((uint8_t) (*paquete).payLoad[i]) * potencia(2, 24)) + (((uint8_t) (*paquete).payLoad[i + 1]) * potencia(2, 16)) + (((uint8_t) (*paquete).payLoad[i + 2]) * potencia(2, 8)));
			(*paquete).payLoad[i + 4] = (paqueteEscritura.payLoad[j].numSector / potencia(2, 24)) - ((((uint8_t) (*paquete).payLoad[i]) * potencia(2, 32)) + (((uint8_t) (*paquete).payLoad[i + 1]) * potencia(2, 24)) + (((uint8_t) (*paquete).payLoad[i + 2]) * potencia(2, 16)) + (((uint8_t) (*paquete).payLoad[i + 3]) * potencia(2, 8)));
			(*paquete).payLoad[i + 5] = (paqueteEscritura.payLoad[j].numSector / potencia(2, 16)) - ((((uint8_t) (*paquete).payLoad[i]) * potencia(2, 40)) + (((uint8_t) (*paquete).payLoad[i + 1]) * potencia(2, 32)) + (((uint8_t) (*paquete).payLoad[i + 2]) * potencia(2, 24)) + (((uint8_t) (*paquete).payLoad[i + 3]) * potencia(2, 16)) + (((uint8_t) (*paquete).payLoad[i + 4]) * potencia(2, 8)));
			(*paquete).payLoad[i + 6] = (paqueteEscritura.payLoad[j].numSector / potencia(2, 8)) - ((((uint8_t) (*paquete).payLoad[i]) * potencia(2, 48)) + (((uint8_t) (*paquete).payLoad[i + 1]) * potencia(2, 40)) + (((uint8_t) (*paquete).payLoad[i + 2]) * potencia(2, 32)) + (((uint8_t) (*paquete).payLoad[i + 3]) * potencia(2, 24)) + (((uint8_t) (*paquete).payLoad[i + 4]) * potencia(2, 16)) + (((uint8_t) (*paquete).payLoad[i + 5]) * potencia(2, 8)));
			(*paquete).payLoad[i + 7] = paqueteEscritura.payLoad[j].numSector - ((((uint8_t) (*paquete).payLoad[i]) * potencia(2, 56)) + (((uint8_t) (*paquete).payLoad[i + 1]) * potencia(2, 48)) + (((uint8_t) (*paquete).payLoad[i + 2]) * potencia(2, 40)) + (((uint8_t) (*paquete).payLoad[i + 3]) * potencia(2, 32)) + (((uint8_t) (*paquete).payLoad[i + 4]) * potencia(2, 24)) + (((uint8_t) (*paquete).payLoad[i + 5]) * potencia(2, 16)) + (((uint8_t) (*paquete).payLoad[i + 6]) * potencia(2, 8)));
			i += 8;

			uint32_t k;
			for (k = 0; (k < 512) && (i < paqueteEscritura.pLength); i++, k++)
				(*paquete).payLoad[i] = ((paqueteEscritura.payLoad[j]).contenidoSector)[k];
		}
		return 0;
	} else
		return 1;
}

//--------------------------------------------------
//MANEJO DE PAQUETES DE LECTURA
//--------------------------------------------------

int8_t paqueteAPaqueteLectura(t_paquete paquete, t_paquete_lectura* paqueteLectura) {
	/*--------------------------------------------------
	 * ESTA FUNCION PASA UNA ESTRUCTURA PAQUETE GENERICO
	 * A UNA PAQUETE DE LECTURA
	 * --------------------------------------------------
	 */
	if (esPaqueteLectura(paquete.type)) {
		(*paqueteLectura).type = paquete.type;
		(*paqueteLectura).pLength = paquete.pLength;
		(*paqueteLectura).payLoad = (uint64_t*) malloc(paquete.pLength / sizeof(uint64_t));
		uint32_t i; //INDICE PARA CHAR
		uint32_t j; //INDICE PARA UINT64_T
		for (i = 0, j = 0; (j < (paquete.pLength / sizeof(uint64_t))) && (i < (paquete.pLength - 7)); i += 8, j++) {
			(*paqueteLectura).payLoad[j] = (((uint8_t) paquete.payLoad[i]) * potencia(2, 56));
			(*paqueteLectura).payLoad[j] += (((uint8_t) paquete.payLoad[i + 1]) * potencia(2, 48));
			(*paqueteLectura).payLoad[j] += (((uint8_t) paquete.payLoad[i + 2]) * potencia(2, 40));
			(*paqueteLectura).payLoad[j] += (((uint8_t) paquete.payLoad[i + 3]) * potencia(2, 32));
			(*paqueteLectura).payLoad[j] += (((uint8_t) paquete.payLoad[i + 4]) * potencia(2, 24));
			(*paqueteLectura).payLoad[j] += (((uint8_t) paquete.payLoad[i + 5]) * potencia(2, 16));
			(*paqueteLectura).payLoad[j] += (((uint8_t) paquete.payLoad[i + 6]) * potencia(2, 8));
			(*paqueteLectura).payLoad[j] += (((uint8_t) paquete.payLoad[i + 7]));
		}
		return 0;
	} else
		return 1;
}

int8_t paqueteLecturaAPaquete(t_paquete_lectura paqueteLectura, t_paquete* paquete) {
	/*--------------------------------------------------
	 * ESTA FUNCION PASA UNA ESTRUCTURA PAQUETE DE LECTURA
	 * A UNA PAQUETE GENERICO
	 * --------------------------------------------------
	 */
	if (esPaqueteLectura(paqueteLectura.type)) {
		(*paquete).type = paqueteLectura.type;
		(*paquete).pLength = paqueteLectura.pLength;
		(*paquete).payLoad = (char*) malloc(paqueteLectura.pLength);
		uint32_t i; //INDICE PARA CHAR
		uint32_t j; //INDICE PARA UINT64_T
		for (i = 0, j = 0; (i < paqueteLectura.pLength - 7) && (j < (paqueteLectura.pLength / sizeof(uint64_t))); i += 8, j++) {
			(*paquete).payLoad[i] = paqueteLectura.payLoad[j] / potencia(2, 56);
			(*paquete).payLoad[i + 1] = (paqueteLectura.payLoad[j] / potencia(2, 48)) - (((uint8_t) (*paquete).payLoad[i]) * potencia(2, 8));
			(*paquete).payLoad[i + 2] = (paqueteLectura.payLoad[j] / potencia(2, 40)) - ((((uint8_t) (*paquete).payLoad[i]) * potencia(2, 16)) + (((uint8_t) (*paquete).payLoad[i + 1]) * potencia(2, 8)));
			(*paquete).payLoad[i + 3] = (paqueteLectura.payLoad[j] / potencia(2, 32)) - ((((uint8_t) (*paquete).payLoad[i]) * potencia(2, 24)) + (((uint8_t) (*paquete).payLoad[i + 1]) * potencia(2, 16)) + (((uint8_t) (*paquete).payLoad[i + 2]) * potencia(2, 8)));
			(*paquete).payLoad[i + 4] = (paqueteLectura.payLoad[j] / potencia(2, 24)) - ((((uint8_t) (*paquete).payLoad[i]) * potencia(2, 32)) + (((uint8_t) (*paquete).payLoad[i + 1]) * potencia(2, 24)) + (((uint8_t) (*paquete).payLoad[i + 2]) * potencia(2, 16)) + (((uint8_t) (*paquete).payLoad[i + 3]) * potencia(2, 8)));
			(*paquete).payLoad[i + 5] = (paqueteLectura.payLoad[j] / potencia(2, 16)) - ((((uint8_t) (*paquete).payLoad[i]) * potencia(2, 40)) + (((uint8_t) (*paquete).payLoad[i + 1]) * potencia(2, 32)) + (((uint8_t) (*paquete).payLoad[i + 2]) * potencia(2, 24)) + (((uint8_t) (*paquete).payLoad[i + 3]) * potencia(2, 16)) + (((uint8_t) (*paquete).payLoad[i + 4]) * potencia(2, 8)));
			(*paquete).payLoad[i + 6] = (paqueteLectura.payLoad[j] / potencia(2, 8)) - ((((uint8_t) (*paquete).payLoad[i]) * potencia(2, 48)) + (((uint8_t) (*paquete).payLoad[i + 1]) * potencia(2, 40)) + (((uint8_t) (*paquete).payLoad[i + 2]) * potencia(2, 32)) + (((uint8_t) (*paquete).payLoad[i + 3]) * potencia(2, 24)) + (((uint8_t) (*paquete).payLoad[i + 4]) * potencia(2, 16)) + (((uint8_t) (*paquete).payLoad[i + 5]) * potencia(2, 8)));
			(*paquete).payLoad[i + 7] = paqueteLectura.payLoad[j] - ((((uint8_t) (*paquete).payLoad[i]) * potencia(2, 56)) + (((uint8_t) (*paquete).payLoad[i + 1]) * potencia(2, 48)) + (((uint8_t) (*paquete).payLoad[i + 2]) * potencia(2, 40)) + (((uint8_t) (*paquete).payLoad[i + 3]) * potencia(2, 32)) + (((uint8_t) (*paquete).payLoad[i + 4]) * potencia(2, 24)) + (((uint8_t) (*paquete).payLoad[i + 5]) * potencia(2, 16)) + (((uint8_t) (*paquete).payLoad[i + 6]) * potencia(2, 8)));
		}
		return 0;
	} else
		return 1;
}
